package com.zh.chat.net;

/*
 服务端原先有很大的局限性
 原先我们没有考虑客户端的文件名,和客户端判断是否有重名文件,我们是另外指定了文件名和路径
 当客户端A连接服务端,被服务端获取到后,服务端执行具体流程,
 这时如果B客户端尝试连接服务端,但只能等待
 因为服务端还没有处理完A客户端的请求,不能回while起始位置执行accept方法,所以
 暂时获取不到B客户端对象,那么为了可以让多个客户端同时被服务端并发接收,
 那么服务端最好就是将每个客户端封装到一个个单独的线程中,这样,就可以同时处理多个客户端请求
 如何定义线程呢?
 只要明确每一个客户端要再服务端执行的代码即可,将该代码放到run方法中
 如果服务端存在同名文件就返回信息并断开该次连接


 如果要让客户端选择是否要覆盖文件,可以再加个反馈操作应该就可以了

 [示例]:传送任意文件 (服务端并发执行)
 */
import java.net.*;
import java.io.*;

import com.zh.chat.controller.ClientContext;
import com.zh.chat.entity.UDPProtocol;

public class FileServer // 服务端
{
	private File file = null;
	private ServerSocket serversock = null;

	public FileServer(ServerSocket server, String path, ClientContext controller, UDPProtocol protocol) throws Exception {
		this.serversock = server; // 监听端口
		this.file = new File(path);
		controller.getNetService().send(protocol);// 发送客户端告知客户端端口号
		Socket sock = serversock.accept(); // 循环等待客户端连接
		FileInputStream fis = new FileInputStream(file); // 读取本地文件
		OutputStream sockOut = sock.getOutputStream(); // 定义socket输出流

		// 先发送文件名.让服务端知道
		String fileName = file.getName();
		System.out.println("待发送文件:" + fileName);
		String serverInfo = readInInfo(sock); // 反馈的信息:客户端是否获取文件名并创建文件成功
		writeOutInfo(sock, fileName+":"+file.length());// 向客户端发送文件名
		if (serverInfo.equals("FileSendNow")) // 客户端说已经准备接收文件,发吧
		{
			serverInfo=readInInfo(sock);
			if(serverInfo.equalsIgnoreCase("ok")){
				byte[] bufFile = new byte[1024];
				int len = 0;
				while (true) {
					len = fis.read(bufFile);
					if (len != -1) {
						sockOut.write(bufFile, 0, len); // 将从硬盘上读取的字节数据写入socket输出流
					} else {
						break;
					}
				}
			}
		}
		serverInfo = readInInfo(sock);
		if(serverInfo.equalsIgnoreCase("over")){
			System.out.println("发送成功:" + fileName);
			fis.close();
			sock.close();
			serversock.close();
		}
	}

	public String readInInfo(Socket sock) throws Exception // 读取服务端的反馈信息
	{
		InputStream sockIn = sock.getInputStream(); // 定义socket输入流
		byte[] bufIn = new byte[1024];
		int lenIn = sockIn.read(bufIn); // 将服务端返回的信息写入bufIn字节缓冲区
		String info = new String(bufIn, 0, lenIn);
		return info;
	}

	public void writeOutInfo(Socket sock, String infoStr) throws Exception// 将信息反馈给服务端
	{
		OutputStream sockOut = sock.getOutputStream();
		sockOut.write(infoStr.getBytes());
	}
}
